package com.app.coderead;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
import java.util.logging.Logger;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.*;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;

/**
 * 展示模擬另一應用程式發出code read request
 * 
 * @author flyman
 * 
 */
@SuppressWarnings("serial")
public class DemoServlet extends HttpServlet {
    private final String CHARSET = "UTF-8";
    // Line separator required by multipart/form-data.
    private final String CRLF = "\r\n";
    private final Logger log;
    private final String TAG;

    {
        TAG = this.getClass().getName();
        log = Logger.getLogger(TAG);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
            IOException {
        processRequest(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        processRequest(req, resp);
    }

    public void processRequest(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        URL url = new URL("http://readtoshow.appspot.com/uploadcode");

        // URL url = new URL("http://localhost:8888/uploadcode");

        // generate some unique random value.
        String boundary = Long.toHexString(System.currentTimeMillis());

        URLConnection connection = url.openConnection();
        connection.setConnectTimeout(10000);
        connection.setReadTimeout(10000);
        connection.setDoOutput(true);
        connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

        OutputStream connectOut = null;
        PrintWriter connectOutWrite = null;

        ServletFileUpload upload = new ServletFileUpload();
        try {
            FileItemIterator uploadItemIterator = upload.getItemIterator(req);

            FileItemStream uploadDataItem = null;
            connectOut = connection.getOutputStream();
            // true = autoFlush
            connectOutWrite = new PrintWriter(new OutputStreamWriter(connectOut, CHARSET), true);

            while (uploadItemIterator.hasNext()) {
                uploadDataItem = uploadItemIterator.next();
                if (uploadDataItem.isFormField()) {
                    String fieldName = uploadDataItem.getFieldName();
                    String fieldValue = Streams.asString(uploadDataItem.openStream());
                    // Send normal param.
                    connectOutWrite.append("--" + boundary).append(CRLF);
                    connectOutWrite.append(
                            "Content-Disposition: form-data; name=\"" + fieldName + "\"").append(
                            CRLF);
                    connectOutWrite.append("Content-Type: text/plain; charset=" + CHARSET).append(
                            CRLF);
                    connectOutWrite.append(CRLF);
                    connectOutWrite.append(fieldValue).append(CRLF).flush();

                } else {// stream
                    // Send binary file.
                    InputStream uploadDataStream = uploadDataItem.openStream();
                    String fileName = uploadDataItem.getName();
                    String fieldName = uploadDataItem.getFieldName();
                    connectOutWrite.append("--" + boundary).append(CRLF);
                    connectOutWrite.append(
                            "Content-Disposition: form-data; name=\"" + fieldName
                                    + "\"; filename=\"" + fileName + "\"").append(CRLF);
                    connectOutWrite.append(
                            "Content-Type: " + URLConnection.guessContentTypeFromName(fileName))
                            .append(CRLF);
                    connectOutWrite.append("Content-Transfer-Encoding: binary").append(CRLF);
                    connectOutWrite.append(CRLF).flush();

                    try {
                        byte[] buffer = new byte[1024];
                        for (int length = 0; (length = uploadDataStream.read(buffer)) > 0;) {
                            connectOut.write(buffer, 0, length);
                        }

                        // Important! Output cannot be closed.
                        // Close of writer will close output as well.
                        connectOut.flush();

                    } finally {
                        if (uploadDataStream != null) {
                            try {
                                // close the stream from user upload file
                                uploadDataStream.close();
                            } catch (IOException e) {
                                log.info("fail to close the stream from user upload file");
                            }
                        }
                    }
                    // CRLF is important! It indicates end of binary boundary.
                    connectOutWrite.append(CRLF).flush();
                    // End of multipart/form-data.
                    connectOutWrite.append("--" + boundary + "--").append(CRLF).flush();

                }
            }

        } catch (FileUploadException e) {
            e.printStackTrace();
        } finally {
            if (connectOutWrite != null)
                connectOutWrite.close();
        }

        // to browser
        resp.setCharacterEncoding(CHARSET);
        BufferedReader connectIn = null;
        // reads the response of connection and output it inside the servlet
        // content
        long time = new Date().getTime();
        log.info("start : " + time);
        try {
            connectIn = new BufferedReader(new InputStreamReader(connection.getInputStream(),
                    CHARSET));
            String line = null;
            StringBuffer sb = new StringBuffer();
            while (null != (line = connectIn.readLine())) {
                sb.append(line).append(CRLF);
            }
            log.info("end : " + (new Date().getTime() - time));
            req.setAttribute("doc", sb);

        } finally {
            if (connectIn != null) {
                connectIn.close();
            }
        }

        RequestDispatcher view = req.getRequestDispatcher("/page/output.jsp");
        view.forward(req, resp);

    }
}
